package ro.ubbcluj.cs.validation.framework.model;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import ro.ubbcluj.cs.validation.framework.core.ParameterName;
import ro.ubbcluj.cs.validation.framework.core.ValidationError;
import ro.ubbcluj.cs.validation.framework.core.ValidationErrorType;

public class DateValidator extends BaseValidator {

	private String[] paramValue;
	private Map<ParameterName, String> validationParameters;
	
	public DateValidator(String[] paramValue, Map<ParameterName, String> validationParameters) {
		this.paramValue = paramValue;
		this.validationParameters = validationParameters;
	}
	
	private ValidationError validateDate(String value, Map<ParameterName, String> validationParameters){
		String pattern = validationParameters.get(ParameterName.pattern);
		if (pattern == null) {
			pattern = "yyyy-MM-dd";
		}
		try {
			if (StringUtils.isNotEmpty(value) && new SimpleDateFormat(pattern).parse(value) == null) {
				return new ValidationError(ValidationErrorType.INVALID_DATE_FORMAT, new String[]{pattern});
			}
		} catch (ParseException e) {
			return new ValidationError(ValidationErrorType.INVALID_DATE_FORMAT, new String[]{pattern});
		}
		return ValidationError.NO_ERRORS;
	}
	
	private ValidationError validateBefore(String value, Map<ParameterName, String> validationParameters){
		String pattern = validationParameters.get(ParameterName.pattern);
		String before = validationParameters.get(ParameterName.before);
		try {
			if (StringUtils.isNotEmpty(value) && before != null && !new SimpleDateFormat(pattern).parse(value).before(new SimpleDateFormat(pattern).parse(before))) {
				return new ValidationError(ValidationErrorType.BEFORE, new String[]{before});
			}
		} catch (ParseException e) {
			return new ValidationError(ValidationErrorType.INVALID_DATE_FORMAT, new String[]{pattern});
		}
		return ValidationError.NO_ERRORS;
	}
	
	private ValidationError validateAfter(String value, Map<ParameterName, String> validationParameters){
		String pattern = validationParameters.get(ParameterName.pattern);
		String after = validationParameters.get(ParameterName.after);
		try {
			if (StringUtils.isNotEmpty(value) && after != null && !new SimpleDateFormat(pattern).parse(value).before(new SimpleDateFormat(pattern).parse(after))) {
				return new ValidationError(ValidationErrorType.AFTER, new String[]{after});
			}
		} catch (ParseException e) {
			return new ValidationError(ValidationErrorType.INVALID_DATE_FORMAT, new String[]{pattern});
		}
		return ValidationError.NO_ERRORS;
	}
	
	private boolean isWeekend(Date date){
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		if (c.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || c.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
			return true;
		}
		return false;
	}
	
	private ValidationError validateWeekday(String value, Map<ParameterName, String> validationParameters){
		String pattern = validationParameters.get(ParameterName.pattern);
		String weekday = validationParameters.get(ParameterName.weekday);
		try {
			if (StringUtils.isNotEmpty(value) && weekday != null && isWeekend(new SimpleDateFormat(pattern).parse(value))) {
				return new ValidationError(ValidationErrorType.NOT_WEEKDAY, null);
			}
		} catch (ParseException e) {
			return new ValidationError(ValidationErrorType.INVALID_DATE_FORMAT, new String[]{pattern});
		}
		return ValidationError.NO_ERRORS;
	}
	
	private ValidationError validateWeekend(String value, Map<ParameterName, String> validationParameters){
		String pattern = validationParameters.get(ParameterName.pattern);
		String weekend = validationParameters.get(ParameterName.weekend);
		try {
			if (StringUtils.isNotEmpty(value) && weekend != null && !isWeekend(new SimpleDateFormat(pattern).parse(value))) {
				return new ValidationError(ValidationErrorType.NOT_WEEKEND, null);
			}
		} catch (ParseException e) {
			return new ValidationError(ValidationErrorType.INVALID_DATE_FORMAT, new String[]{pattern});
		}
		return ValidationError.NO_ERRORS;
	}
	
	public List<ValidationError> validate() {
		List<ValidationError> errors = new ArrayList<ValidationError>();
		for(String value : paramValue){
			ValidationError requiredCheck = validateRequired(value, validationParameters);
			if (requiredCheck != ValidationError.NO_ERRORS) {
				errors.add(requiredCheck);
			} else {
				ValidationError dateCheck = validateDate(value, validationParameters);
				if (dateCheck != ValidationError.NO_ERRORS) {
					errors.add(dateCheck);
				} else {
					ValidationError beforeCheck = validateBefore(value, validationParameters);
					ValidationError afterCheck = validateAfter(value, validationParameters);
					ValidationError weekdayCheck = validateWeekday(value, validationParameters);
					ValidationError weekendCheck = validateWeekend(value, validationParameters);
					if (beforeCheck != ValidationError.NO_ERRORS) {
						errors.add(beforeCheck);
					}
					if (afterCheck != ValidationError.NO_ERRORS) {
						errors.add(afterCheck);
					}
					if (weekdayCheck != ValidationError.NO_ERRORS) {
						errors.add(weekdayCheck);
					}
					if (weekendCheck != ValidationError.NO_ERRORS) {
						errors.add(weekendCheck);
					}
				}
			}
		}		
		return errors;
	}

	public final String[] getParamValue() {
		return paramValue;
	}

	public final void setParamValue(String[] paramValue) {
		this.paramValue = paramValue;
	}

	public final Map<ParameterName, String> getValidationParameters() {
		return validationParameters;
	}

	public final void setValidationParameters(Map<ParameterName, String> validationParameters) {
		this.validationParameters = validationParameters;
	}
}
